package fr.inria.gforge.spoon.analysis;

import spoon.processing.AbstractProcessor;
import spoon.reflect.code.CtConstructorCall;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.reference.CtExecutableReference;
import spoon.reflect.reference.CtTypeReference;

import java.util.ArrayList;
import java.util.List;

public class FactoryProcessor extends AbstractProcessor<CtConstructorCall<?>> {

    public List<CtConstructorCall> listWrongUses = new ArrayList<>();
    private CtTypeReference factoryTypeRef;

    public FactoryProcessor(CtTypeReference factoryTypeRef) {
        this.factoryTypeRef = factoryTypeRef;
    }

    public void process(CtConstructorCall<?> newClass) {
        // skip factory creation
        if (newClass.getExecutable().getDeclaringType().isSubtypeOf(getFactoryType()))
            return;
        // skip creations in factories
        if (newClass.getParent(CtClass.class).isSubtypeOf(getFactoryType()))
            return;
        // only report for types created by the factory
        for (CtTypeReference<?> t : getCreatedTypes()) {
            if (newClass.getType().isSubtypeOf(t)) {
                this.listWrongUses.add(newClass);
            }
        }

    }

    protected CtTypeReference<?> getFactoryType() {
        return this.factoryTypeRef;
    }

    List<CtTypeReference<?>> createdTypes;

    private List<CtTypeReference<?>> getCreatedTypes() {
        if (createdTypes == null) {
            createdTypes = new ArrayList<CtTypeReference<?>>();
            for (CtExecutableReference<?> m : getFactoryType().getDeclaredExecutables()) {
                createdTypes.add(m.getType());
            }
        }
        return createdTypes;
    }

}
